package com.ckzp.core.util;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.jwt.JWT;
import com.alibaba.fastjson.JSON;
import com.ckzp.core.ConfigUtil;
import com.ckzp.core.Results;
import com.ckzp.jfinal.system.util.LoginUtil;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * Created by 51594 on 2022/7/27.
 */
public class JwtUtil {


    public static String JWT_KEY = "eyJhbGciOiJIUzI1NiJ9";

    /**
     *
     */
    public static long EXP_DATE = 24 * 60 * 60 * 1000;
    /**
     *
     */
    protected static boolean DEBUG = ConfigUtil.DEBUG();

    /**
     * 签发JWT
     *
     * @param id
     * @param subject   可以是JSON数据 尽可能少
     * @param ttlMillis
     * @return String
     */
    public static String createJWT(String id, JwtSubject subject, long ttlMillis) {
        return createJWT(id, subject.toJson(), ttlMillis);
    }


    /**
     * 签发JWT
     *
     * @param uid
     * @return String
     */
    public static String createJWT(String uid) {
        JwtUtil.JwtSubject js = new JwtUtil.JwtSubject();
        js.setUserid(uid);
        return createJWT("jwt", js, EXP_DATE);
    }

    /**
     * 签发JWT
     *
     * @param id
     * @param subject   可以是JSON数据 尽可能少
     * @param ttlMillis
     * @return String
     */
    public static String createJWT(String id, String subject, long ttlMillis) {
        Date issuedAt = DateTime.now();
        Date expiredAt = new Date(System.currentTimeMillis() + 5 * 3600 * 1000);//默认 5小时
        if (ttlMillis > 0) expiredAt = new Date(System.currentTimeMillis() + ttlMillis);//传入的时间，单位秒
        Date notBefore = new Date(System.currentTimeMillis() - 5 * 1000);
        byte[] key = JWT_KEY.getBytes();
        return JWT.create()
                .setKey(key)
                .setIssuedAt(issuedAt)//设置签发时间
                .setExpiresAt(expiredAt)//过期时间
                .setNotBefore(notBefore)//生效时间,不能晚于当前
                .setPayload("info", subject)
                .sign();
    }

    /**
     * 验证JWT
     *
     * @param jwtStr
     * @return
     */
    public static Results validateJWT(String jwtStr) {
        Results result = new Results(0);
        if (StrUtil.isBlank(jwtStr)) return result.setCode(92).setMsg("无效TOKEN");
        JWT jwt = JWT.of(jwtStr).setKey(JWT_KEY.getBytes());
        if (!jwt.verify()) return result.setCode(92).setMsg("无效TOKEN");
        if (!jwt.validate(0)) result.setCode(91).setMsg("登陆已过期");
        if (JwtPool.checkJwt(jwtStr)) return result.setCode(95).setMsg("登陆已注销")
                .setMessage("登陆已注销").setObject(new JwtSubject());
        result.setCode(0).setMsg("验证成功");
        String info = String.valueOf(jwt.getPayload("info"));
        result.setObject(JSONUtil.toBean(info, JwtSubject.class));
        return result;
    }

    /**
     * 信息
     *
     * @param jwtStr
     * @return
     */
    public static JwtSubject getJwtInfo(String jwtStr) {
        Results result = validateJWT(jwtStr);
        try {
            return result.getObject(JwtUtil.JwtSubject.class);
        } catch (Exception e) {
            e.printStackTrace();
            return new JwtSubject();
        }
    }

    /**
     * 从head中取jwt
     *
     * @param request
     * @return
     */
    public static JwtSubject getJwtInfo(HttpServletRequest request) {
        Results result = validateJWT(request.getHeader("X-Jwt-Token"));
        try {
            return result.getObject(JwtUtil.JwtSubject.class);
        } catch (Exception e) {
            return new JwtSubject();
        }
    }


    /**
     * 取得jwt用户信息
     *
     * @param jwt
     * @return
     */
    public static String getUserId(String jwt) {
        if (jwt == null || jwt.length() == 0) return "";
        Results results = JwtUtil.validateJWT(jwt);
        if (results.getCode() == 0) {
            JwtUtil.JwtSubject js = results.getObject(JwtUtil.JwtSubject.class);
            return js.getUserid();
        }
        return "";
    }

    /**
     * @param result
     * @return
     */
    public static JwtSubject getJwtInfo(Results result) {
        try {
            return result.getObject(JwtUtil.JwtSubject.class);
        } catch (Exception e) {
            return new JwtSubject();
        }
    }

    /**
     * @return
     */
    public static SecretKey generalKey() {
        byte[] encodedKey = ConfigUtil.getProperty("JWT_SECERT", "DEFAULT_KEY_9423156").getBytes();
        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
        return key;
    }


    public static class JwtSubject {

        public String id;//会话ID
        public String userid = "";
        public int pid = 0;
        public int deptid = 0;
        public int orgid = 0;
        public int tempid = 0;
        public String username;
        public String roles;
        public String posts;
        public long lastlogin = 0;

        public JwtSubject() {
        }

        public JwtSubject(String id) {
            this.id = id;
        }


        public JwtSubject setId(String id) {
            this.id = id;
            return this;
        }

        public JwtSubject(String userid, String username, String roles) {
            this.userid = userid;
            this.username = username;
            this.roles = roles;
        }

        public JwtSubject(String userid, int deptid, String username, String roles) {
            this.userid = userid;
            this.deptid = deptid;
            this.username = username;
            this.roles = roles;
        }


        public JwtSubject(String userid, int deptid, String username, String roles, long lastlogin) {
            this.userid = userid;
            this.deptid = deptid;
            this.username = username;
            this.roles = roles;
            this.lastlogin = lastlogin;
        }

        public int getPid() {
            return pid;
        }

        public String getId() {
            return id;
        }

        public void setPid(int pid) {
            this.pid = pid;
        }

        public String getUserid() {
            return userid;
        }

        public void setUserid(String userid) {
            this.userid = userid;
        }

        public int getDeptid() {
            return deptid;
        }

        public void setDeptid(int deptid) {
            this.deptid = deptid;
        }

        public int getOrgid() {
            return orgid;
        }

        public void setOrgid(int orgid) {
            this.orgid = orgid;
        }

        public int getTempid() {
            return tempid;
        }

        public void setTempid(int tempid) {
            this.tempid = tempid;
        }

        public String getUsername() {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        public String getRoles() {
            return roles;
        }

        public void setRoles(String roles) {
            this.roles = roles;
        }

        public String getPosts() {
            return posts;
        }

        public void setPosts(String posts) {
            this.posts = posts;
        }

        public long getLastlogin() {
            return lastlogin;
        }

        public void setLastlogin(long lastlogin) {
            this.lastlogin = lastlogin;
        }

        public String toJson() {
            return JSON.toJSONString(this);
        }
    }


    /**
     * jwt黑名单
     */
    public static class JwtPool {
        private static List JWTLIST = new ArrayList();

        public static void AddJwt(String jwt) {
            JWTLIST.add(jwt);
        }

        /**
         * @param jwt
         * @return
         */
        public static boolean checkJwt(String jwt) {
            for (int k = 0; k < JWTLIST.size(); k++) {
                String jwts = String.valueOf(JWTLIST.get(k));
                if (jwt.equals(jwts)) {
                    return true;
                }
            }
            return false;
        }
    }

    public static void main(String[] arg) {
//        String jwt = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIxMDAwMSIsInN1YiI6IntcImRlcHRpZFwiOjk5OTksXCJpZFwiOlwiNDAyODhhZjc4YjVmNzFiNzAxOGI1Zjc1MjkyNjAwMDJcIixcImxhc3Rsb2dpblwiOjE2OTgxMTM1OTU2ODYsXCJvcmdpZFwiOjEwMSxcInBpZFwiOjAsXCJwb3N0c1wiOlwifHwyfDF8fFwiLFwicm9sZXNcIjpcInxhZG1pbmlzdHJhdG9yfGFyZWFhZG1pbnxhcnRpY2xlYWRtaW58YnJhbmNoYWRtaW58Y2l0eWFkbWlufGdvb2RzYWRtaW58Z3JvdXBhZG1pbnxqZmFkbWlufGxvZ2lufHN5c3RlbXx3ZWl4aW58XCIsXCJ0ZW1waWRcIjowLFwidXNlcmlkXCI6MTAwMDEsXCJ1c2VybmFtZVwiOlwid3V5YW5nXCJ9IiwiaXNzIjoidXNlciIsImlhdCI6MTY5ODExMzU5NSwiZXhwIjoxNjk4MTM1MTk1fQ.pQT0Xu1vRO4vZQFQu1C1rFU9HdwzUUTcO7JLsjRj3aU";
//        jwt = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIxMDAwMSIsInN1YiI6IntcImRlcHRpZFwiOjk5OTksXCJpZFwiOlwiNDAyODgwZWE4YjYwZGIwZTAxOGI2MGRiNTI5MDAwMDFcIixcImxhc3Rsb2dpblwiOjE2OTgxMzcwNjgxNzYsXCJvcmdpZFwiOjEwMSxcInBpZFwiOjAsXCJwb3N0c1wiOlwifHwyfDF8fFwiLFwicm9sZXNcIjpcInxhZG1pbmlzdHJhdG9yfGFyZWFhZG1pbnxhcnRpY2xlYWRtaW58YnJhbmNoYWRtaW58Y2l0eWFkbWlufGdvb2RzYWRtaW58Z3JvdXBhZG1pbnxqZmFkbWlufGxvZ2lufHN5c3RlbXx3ZWl4aW58XCIsXCJ0ZW1waWRcIjowLFwidXNlcmlkXCI6MTAwMDEsXCJ1c2VybmFtZVwiOlwid3V5YW5nXCJ9IiwiaXNzIjoidXNlciIsImlhdCI6MTY5ODEzNzA2OCwiZXhwIjoxNjk4NjU1NDY4fQ.77gQWziKScoxdREiSO9FWKo4cSmP1c6GcF7YYthgEg4";
//        JwtSubject subject = JwtUtil.getJwtInfo(jwt);
//        System.out.println(subject);

        JwtSubject js = new JwtSubject();
        js.setUserid("45");
        String s = JwtUtil.createJWT("ffff", js, LoginUtil.EXPRESS_LOGIN_TIME);
        System.out.println(s);
        Results results = JwtUtil.validateJWT(s);
        System.out.println(JwtUtil.getJwtInfo(s).getUserid());
        System.out.println(results.toJson());
    }

}
